#!python
# -*- coding: utf-8 -*-

from google.appengine.api import images
from google.appengine.api import users
from google.appengine.ext import db

from common import redirect, respond
from models import Album, Picture
from django.http import HttpResponse
from django.http import Http404
from django.http import HttpResponseNotModified

from datetime import datetime, timedelta, date
import cgi
import random
import re

from django.utils.translation import ugettext as _

_params = {'menu_album': True,
           'title': _("picture"),}

GMT_FORMAT = "%a, %d %b %Y %H:%M:%S GMT" # Thu, 01 Dec 1994 16:00:00 GMT

def home(request):
    pic = Picture.random()
    if pic is None:
        return redirect("/")

    params = _params.copy()
    params.update({'pic': pic,
                   'title': pic.title,
                   'randomized': True,})
    return respond('picture_detail.html', params)

def edit(request, pic_id):
    """
    two things.
     - repond the picture edit form page, which should be a GET method. or
     - process the edit form, which should be POST.

    please note this method differs from the update method.
    `edit` edits the picture informations. `update` updates the picture itself.
    """
    try:
        pic = get_picture(pic_id, check_authority=True)
    except Exception:
        return redirect('/picture/%s' % pic_id)

    if request.method == "GET":
        params = _params.copy()
        params.update({'pic': pic, 'title': pic.title,})
        return respond('picture_edit.html', params)
    elif request.method == "POST":
        pic.title = request.POST.get('title')
        pic.caption = request.POST.get('caption')
        tags = request.POST.get('tags').split(' ')
        pic.tags = [tag.strip() for tag in tags]
        pic.put()
        return respond('redirect.html', {'redirect': '/picture/%s' % pic_id,
                                         'msg': _("picture update success"),
                                         'pic': pic,})

def delete(request, pic_id):
    try:
        pic = get_picture(pic_id, check_authority=True)
    except Exception:
        return redirect('/picture/%s' % pic_id)

    if request.GET.has_key('confirm'):
        album = pic.album
        pic.delete()
        return respond('redirect.html', {'redirect': '/album/%s' % album.key().id(),
                                         'msg': _("picture delete success"),})
    else:
        return respond('confirm.html', {'confirm_url': '/picture/%s/delete?confirm' % pic_id,
                                        'cancel_url': '/picture/%s' % pic_id,
                                        'pic': pic,
                                        'title': pic.title})

def slug(request, year, month, day, title):
    year = int(year)
    month = int(month)
    day = int(day)
    submitted_date = date(year, month, day)
    query = Picture.all()
    query.filter('submitted_date >', submitted_date)
    query.filter('submitted_date <', submitted_date + timedelta(days=1))
    query.filter('title =', title)
    if query.count() > 1 or query.count() == 0:
        return redirect('/album')

    pic = query.get()
    return slide(request, pic.key().id())

def slide(request, pic_id):
    """
    picture detail page.
    """
    current_pic = get_picture(pic_id)
    if request.GET.has_key('simple'):
        return respond('picture_simple.html', {'pic': current_pic,})

    index, previous_pic, next_pic = get_neighbor(current_pic)

    params = _params.copy()
    params.update({'pic': current_pic,
                   'album': current_pic.album,
                   'next_pic': next_pic,
                   'previous_pic': previous_pic,
                   'title': current_pic.title,
                   'index': index +1,})
    return respond('picture_detail.html', params)

def update(request, pic_id):
    """
    picture re-upload.
    """
    try:
        pic = get_picture(pic_id, check_authority=True)
    except:
        return redirect('/picture/%s' % pic_id)

    if request.method == 'GET':
        params = _params.copy()
        params.update({'title': pic.title,
                       'pic': pic,
                       'picture_update': True,})
        return respond('picture_upload.html', params)
    elif request.method == 'POST':
        my_file = request.FILES.get('picfile')
        try:
            pic = Picture.process_upload(my_file, picture=pic)
            return feedback(pic, msg=_("upload success"))
        except images.BadImageError:
            return feedback(pic, err=_("bad image"))
        except images.NotImageError:
            return feedback(pic, err=_("not image"))
        except images.LargeImageError:
            return feedback(pic, err=_("large_image"))

def serve(request, pic_id, size=None):
    """
    serve all pictures, including the original, the resized large and the thumbnails
    urls should be like /picture/<pic_id>_<size>.jpg
    """
    if is_hotlink(request):
        return redirect('/statics/cover.jpg')

    pic = get_picture(int(pic_id))
    if no_need(request, pic):
        return HttpResponseNotModified()

    response = HttpResponse()
    response['Content-Type'] = 'image/jpeg'
    response['Cache-Control'] = 'max-age=%d, must-revalidate' % 220752000 # 365 *24 *60 *60 == 7 years
    response['Last-Modified'] = pic.submitted_date.strftime(GMT_FORMAT)
    response['ETag'] = '"%s"' % (pic.etag,)

    if size is None:
        response.write(pic.data)

    elif size =='l':
        if pic.large_data is None:
            response.write(pic.data)
        else:
            response.write(pic.large_data)
    elif size =='m':
        if pic.middle_data is None:
            response.write(pic.data)
        else:
            response.write(pic.middle_data)
    elif size =='t':
        if pic.thumbnail_data is None:
            response.write(pic.data)
        else:
            response.write(pic.thumbnail_data)

    return response

def rehab(request):
    pics = Picture.all()
    for pic in pics:
        if pic.middle_data is not None:
            pic.resize()
    return respond('redirect.html', {'redirect': '/',
                                     'msg': _("picture maintanence success")})

def no_need(request, pic):
    """
    checks the HTTP Header info come from request.
    these two deal with HTTP 1.0 and HTTP 1.1.
    """
    if request.META.has_key('HTTP_IF_MODIFIED_SINCE'):
        # ie pass more than a gmt date. it has something like "; length=blah" appended.
        last_seen = request.META.get('HTTP_IF_MODIFIED_SINCE').split(';')[0]
        last_seen = datetime.strptime(last_seen, GMT_FORMAT)
        if last_seen >= pic.submitted_date.replace(microsecond=0):
            return True

    if request.META.has_key('HTTP_IF_NONE_MATCH'):
        etags = [x.strip('" ')
                 for x in request.META.get('HTTP_IF_NONE_MATCH').split(',')]
        if pic.etag in etags: return True

    return False

def is_hotlink(request):
    """
    we should prevent hotlinks, because lomoo isn't and won't be a picture farm.
    """
    from django.conf import settings
    if settings.DEBUG:
        return False

    referer = request.META.get('HTTP_REFERER')
    empty_ptn = re.compile('^\s*$')
    if referer is None or re.match(empty_ptn, referer):
        return False

    from_lomoo_ptn = re.compile('^http://(www\.|jakes)?lomoo\.(org|appspot\.com)')
    if re.match(from_lomoo_ptn, referer):
        return False

    return True

def get_picture(pic_id, check_authority=False):
    """
    should this method in `models.py` or not?
    """
    pic = Picture.get_by_id(int(pic_id))
    if pic is None:
        raise Http404
    elif check_authority and pic.submitter != users.get_current_user():
        raise Exception('authorize_error')
    else:
        return pic

def get_neighbor(current_pic):
    """
    provides the ability of `previous` and `next`. current solution is not so efficient.
    """
    pics = current_pic.album.pictures
    if pics.count() <=1:
        return 0, None, None

    pic_ids = []
    for pic in pics:
        pic_ids.append(pic.key().id())

    index = pic_ids.index(current_pic.key().id())
    next_pic_id = pic_ids[0]
    if index <len(pic_ids) -1:
        next_pic_id = pic_ids[index+1]

    previous_pic_id = pic_ids[-1]
    if index >=1:
        previous_pic_id = pic_ids[index-1]

    return index, Picture.get_by_id(previous_pic_id), Picture.get_by_id(next_pic_id)

def feedback(pic, **kargs):
    """
    unified `feedback` function for interacting with users in processes
    like picture uploading, description editing and so on.
    """
    params = {'redirect': '/picture/%s' % pic.key().id(),
              'pic': pic,}
    if kargs.get('err'):
        params.update({'err': kargs.get('err')})
    elif kargs.get('msg'):
        params.update({'msg': kargs.get('msg')})
    return respond('redirect.html', params)
